package com.my.auth.security.filter;

import com.my.auth.common.UrlUtils;
import com.my.auth.security.LoginContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;

/**
 * @author zhaodongchao
 * @date 2020/3/28 17:28
 **/
public class BcloudFilterChainProxy extends GenericFilterBean {
    private final static String FILTER_APPLIED = BcloudFilterChainProxy.class.getName().concat(".APPLIED");

    private static final Log logger = LogFactory.getLog(BcloudFilterChainProxy.class);

    private final List<Filter> filters ;

    public BcloudFilterChainProxy(List<Filter> filters) {
        this.filters = filters;
    }


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;

        if (clearContext) {
            try {
                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
                doFilterInternal(request, response, chain);
            } finally {
                LoginContextHolder.clearContext();
                request.removeAttribute(FILTER_APPLIED);
            }
        } else {
            doFilterInternal(request, response, chain);
        }
    }

    private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (filters == null || filters.isEmpty()) {
            chain.doFilter(request, response);
        } else {
            //执行自定义filter，自定义filter执行完之后，再执行自带的filter
            VirtualFilterChain vfc = new VirtualFilterChain(chain, filters);
            vfc.doFilter(request, response);
        }

    }



    /**
     * Internal {@code FilterChain} implementation that is used to pass a request through
     * the additional internal list of filters which match the request.
     *
     * 执行自定义的filter
     */
    private static class VirtualFilterChain implements FilterChain {
        /**
         * web容器自带的filter链
         */
        private final FilterChain originalChain;
        /**
         * 自定义的安全filters
         */
        private final List<Filter> additionalFilters;

        private final int size;
        private int currentPosition = 0;

        private VirtualFilterChain(FilterChain chain, List<Filter> additionalFilters) {
            this.originalChain = chain;
            this.additionalFilters = additionalFilters;
            this.size = additionalFilters.size();
        }

        @Override
        public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
            //如果当前执行的位置等于自定义的filter的个数，说明自定的filter已经执行完毕
            if (currentPosition == size) {
                if (logger.isDebugEnabled()) {
                    logger.debug(UrlUtils.buildRequestUrl((HttpServletRequest) request) + " reached end of additional filter chain; proceeding with original chain");
                }
                //自定的执行完毕之后，然后开始执行原始的filter
                originalChain.doFilter(request, response);
            } else {
                //执行自定义的filter
                currentPosition++;

                Filter nextFilter = additionalFilters.get(currentPosition - 1);

                if (logger.isDebugEnabled()) {
                    logger.debug(UrlUtils.buildRequestUrl((HttpServletRequest) request)
                            + " at position " + currentPosition + " of " + size
                            + " in additional filter chain; firing Filter: '"
                            + nextFilter.getClass().getSimpleName() + "'");
                }

                nextFilter.doFilter(request, response, this);
            }
        }
    }
}


